package de.zainodis.triplog.data;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import de.zainodis.triplog.data.persistence.ILocationDao;
import de.zainodis.triplog.data.persistence.ITripDao;
import de.zainodis.triplog.data.share.TriplogContract;
import de.zainodis.triplog.util.DateTimeUtils;
import de.zainodis.triplog.util.Utilities;

/**
 * Created by fzarrai on 8/18/2014.
 */
@DatabaseTable(tableName = ILocationDao.TABLE_NAME, daoClass = ILocationDao.LocationDao.class)
public class LocationEntry implements Parcelable, ICrudOperations {

    private static final String TAG = "Location";

    @DatabaseField(generatedId = true, columnName = ILocationDao.COLUMN_ID)
    private long id;
    @DatabaseField(columnName = ILocationDao.COLUMN_FK_TRIP)
    private long fkTrip;
    @DatabaseField(columnName = ILocationDao.COLUMN_COORD_LAT)
    private double latitude;
    @DatabaseField(columnName = ILocationDao.COLUMN_COORD_LONG)
    private double longitude;
    @DatabaseField(columnName = ILocationDao.COLUMN_CITY_NAME)
    private String cityName;
    //The location string used to request updates from the server.
    @DatabaseField(columnName = ILocationDao.COLUMN_LOCATION_SETTING)
    private String locationSetting;
    //Weather entries for this location
    private List<WeatherEntry> weatherEntries;


    public LocationEntry() {
    }

    public LocationEntry(ContentValues values) {
        id = Utilities.getAsLong(values, ILocationDao.COLUMN_ID);
        latitude = Utilities.getAsDouble(values, ILocationDao.COLUMN_COORD_LAT);
        longitude = Utilities.getAsDouble(values, ILocationDao.COLUMN_COORD_LONG);
        cityName = Utilities.getAsString(values, ILocationDao.COLUMN_CITY_NAME);
        locationSetting = Utilities.getAsString(values, ILocationDao.COLUMN_LOCATION_SETTING);
        fkTrip = Utilities.getAsLong(values, ILocationDao.COLUMN_FK_TRIP);
    }

    public LocationEntry(Cursor cursor) {
        if (cursor != null) {
            id = cursor.getLong(cursor.getColumnIndex(ILocationDao.COLUMN_ID));
            fkTrip = cursor.getLong(cursor.getColumnIndex(ILocationDao.COLUMN_FK_TRIP));
            latitude = cursor.getDouble(cursor.getColumnIndex(ILocationDao.COLUMN_COORD_LAT));
            latitude = cursor.getDouble(cursor.getColumnIndex(ILocationDao.COLUMN_COORD_LONG));
            cityName = cursor.getString(cursor.getColumnIndex(ILocationDao.COLUMN_CITY_NAME));
            locationSetting = cursor.getString(cursor.getColumnIndex(ILocationDao.COLUMN_LOCATION_SETTING));
        }
    }

    /**
     * @return ContentValues for this LocationEntry.
     */
    public ContentValues getContentValues() {
        ContentValues values = new ContentValues();
        values.put(ILocationDao.COLUMN_LOCATION_SETTING, locationSetting);
        values.put(ILocationDao.COLUMN_CITY_NAME, cityName);
        values.put(ILocationDao.COLUMN_COORD_LAT, latitude);
        values.put(ILocationDao.COLUMN_COORD_LONG, longitude);
        values.put(ILocationDao.COLUMN_ID, id);
        values.put(ILocationDao.COLUMN_FK_TRIP, fkTrip);

        return values;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeLong(id);
        out.writeLong(fkTrip);
        out.writeDouble(latitude);
        out.writeDouble(longitude);
        out.writeString(cityName);
        out.writeString(locationSetting);
    }

    public static final Parcelable.Creator<LocationEntry> CREATOR
            = new Parcelable.Creator<LocationEntry>() {
        public LocationEntry createFromParcel(Parcel in) {
            return new LocationEntry(in);
        }

        public LocationEntry[] newArray(int size) {
            return new LocationEntry[size];
        }
    };

    private LocationEntry(Parcel in) {
        id = in.readLong();
        fkTrip = in.readLong();
        latitude = in.readDouble();
        longitude = in.readDouble();
        cityName = in.readString();
        locationSetting = in.readString();

    }

    public long getId() {
        return id;
    }

    public long getFkTrip() {
        return fkTrip;
    }

    public void setFkTrip(long fkTrip) {
        this.fkTrip = fkTrip;
    }

    public double getLongitude() {
        return longitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }

    public double getLatitude() {
        return latitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public String getLocationSetting() {
        return locationSetting;
    }

    public void setLocationSetting(String locationSetting) {
        this.locationSetting = locationSetting;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    public List<WeatherEntry> getWeatherEntries() {
        return weatherEntries != null ? weatherEntries : new ArrayList<WeatherEntry>();
    }

    public void setWeatherEntries(List<WeatherEntry> weatherEntries) {
        this.weatherEntries = weatherEntries;
    }


    public int delete(Context context) {
        int count = 0;
        if (id > 0) {
            //Delete the location from the database, the content provider will take care of deleting related data
            count = context.getContentResolver().delete(TriplogContract.buildTripUri(id), ITripDao.COLUMN_ID + " = ?",
                    new String[]{String.valueOf(id)});
        }
        return count;
    }

    @Override
    public long createOrUpdate(Context context) {
        if (context == null) {
            Log.e(TAG, "Provided context is null.");
            return -1;
        }
        Cursor cursor = context.getContentResolver().query(
                TriplogContract.CONTENT_URI_LOCATION, new String[]{ILocationDao.COLUMN_ID}, ILocationDao.COLUMN_ID + " = ?",
                new String[]{String.valueOf(getId())},
                null);

        if (cursor.moveToFirst()) {
            id = cursor.getLong(cursor.getColumnIndex(ILocationDao.COLUMN_ID));
        } else {
            //Insert
            Uri uri = context.getContentResolver().insert(TriplogContract.CONTENT_URI_LOCATION, getContentValues());
            id = ContentUris.parseId(uri);
        }

        if (id > 0 && getWeatherEntries().size() > 0) {
            for (WeatherEntry entry : getWeatherEntries()) {
                entry.setFkLocationEntry(id);
                entry.createOrUpdate(context);
            }
        }
        return id;
    }

    /**
     * @param id trip id.
     * @return the location linked to the given trip id; null if there is none.
     */
    public static LocationEntry getByTripId(Context context, long id) {
        Cursor cursor = context.getContentResolver().query(
                TriplogContract.CONTENT_URI_LOCATION, null, ILocationDao.COLUMN_FK_TRIP + " = ?",
                new String[]{String.valueOf(id)},
                null);
        if (cursor.moveToFirst()) {
            LocationEntry entry = new LocationEntry();
            entry.setFkTrip(id);
            entry.setLocationSetting(cursor.getString(cursor.getColumnIndex(ILocationDao.COLUMN_LOCATION_SETTING)));
            entry.id = cursor.getLong(cursor.getColumnIndex(ILocationDao.COLUMN_ID));
            entry.setCityName(cursor.getString(cursor.getColumnIndex(ILocationDao.COLUMN_CITY_NAME)));
            entry.setLatitude(cursor.getDouble(cursor.getColumnIndex(ILocationDao.COLUMN_COORD_LAT)));
            entry.setLongitude(cursor.getDouble(cursor.getColumnIndex(ILocationDao.COLUMN_COORD_LONG)));

            //Find matching weather entries
            entry.setWeatherEntries(WeatherEntry.getByLocationId(context, entry.getId()));

            return entry;
        }
        return null;
    }

    /**
     * @return number of weather entries that are currently pre-loaded, starting from today. Past entries are not considered.
     */
    public int getWeatherCount() {
        int count = 0;
        final long today = Long.valueOf(DateTimeUtils.toDbDateString(new Date()));
        for (WeatherEntry entry : getWeatherEntries()) {
            long day = Long.valueOf(entry.getDate());

            if(day >= today){
                count++;
            }
        }
        return count;
    }

    /**
     * @return the weather for today, for this location; null if there is no weather data available for today and/or this location.
     */
    public WeatherEntry getTodaysWeather() {
        String today = DateTimeUtils.toDbDateString(new Date());
        for (WeatherEntry entry : getWeatherEntries()) {
            if (today.equals(entry.getDate())) {
                return entry;
            }
        }
        return null;
    }
}